package dao.hibernate;


import java.util.List;
import javax.annotation.PostConstruct;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Conjunction;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Subqueries;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import dao.IDaoAsof;
import service.configuration.IConfiguration;
import service.configuration.IPersonSheetConfig;
import service.configuration.ISheetConfig;
import service.configuration.NamingUtil;
import entities.Delegation;
import entities.LinkAssociation;
import entities.OwnerAssociation;
import entities.Sheet;
import entities.SmallSheet;
import entities.TreeAssociation;



@Service
public class DaoHibernateAsof extends DaoHibernate implements IDaoAsof {
	
	@Autowired
	public DaoHibernateAsof(HibernateUtilAsof hibernateUtil, SheetFactory sheetFactory,
			IConfiguration config) {
	
		super(hibernateUtil, sheetFactory, config);
		// generateSampleData();
	}

	@PostConstruct
	public void init() {
		/*
		 * for(ISheetConfig sheetConfig : config.getAllSheetConfigs()) { //
		 * récupère la liste des fiches pour ce type dans REF et ASOF :
		 * sheetsAsof.addAll(findAllSheets(sheetConfig.getName())); }
		 */
	}

	
	/**
	 * Génère et ajoute à la base des fiches de chaque type,
	 * avec pour chaque champs le nom du champs comme valeur.
	 */
	public void generateSampleData() {
		for (int i = 1; i < 11; i++) {
			IPersonSheetConfig personSheetConfig = config.getConfig()
					.getPersonSheetConfig();
			Sheet sheet = SheetFactory.createSampleSheet(personSheetConfig,
					personSheetConfig.getName() + i,
					personSheetConfig.getName());
			addSheet(sheet);
		}

		for (ISheetConfig sheetConfig : config.getConfig().getSheetConfigs()) {
			for (int i = 1; i < 11; i++) {
				Sheet sheet = SheetFactory.createSampleSheet(sheetConfig,
						sheetConfig.getName() + i, sheetConfig.getName());
				addSheet(sheet);
			}
		}
	}



	private <T> void add(T object) {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();
			session.save(object);
			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}


	private <T> void add(List<T> objects) {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;
		int i = 0;

		try {
			transaction = session.beginTransaction();

			for (T object : objects) {
				session.save(object);

				// batch :
				if (++i % hibernateUtil.getJdbcBatchSize() == 0) {
					session.flush();
					session.clear();
				}
			}

			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}


	private <T> void removeById(long id, Class<T> clazz) {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();
			Query query = session.createQuery(
					"delete from " + clazz.getName() + " c where c.id = :id")
					.setParameter("id", id);
			query.executeUpdate();
			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}


	private <T> void remove(T object) {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();
			session.delete(object);
			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}


	private <T> void remove(List<T> objects) {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;
		int i = 0;

		try {
			transaction = session.beginTransaction();

			for (T object : objects) {
				session.delete(object);

				// batch :
				if (++i % hibernateUtil.getJdbcBatchSize() == 0) {
					session.flush();
					session.clear();
				}
			}

			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}

	
	private <T> void removeByIds(List<Long> ids, Class<T> clazz) {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();
			Query query = session.createQuery(
					"delete from " + clazz.getName() + " where id in (:ids)")
					.setParameterList("ids", ids);
			query.executeUpdate();

			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}


	private <T> void removeAll(Class<T> clazz) {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();
			String query = "delete from " + clazz.getName();

			session.createQuery(query).executeUpdate();

			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}


	private <T> List<T> findAll(Class<T> clazz) {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();
			Criteria criteria = session.createCriteria(clazz);
			@SuppressWarnings("unchecked")
			List<T> list = criteria.list();
			return list;
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}



	/**
	 * Ajoute un lien de délégation.
	 * 
	 * @param delegation	un objet délégation à ajouter
	 */
	public void addDelegation(Delegation delegation) {
		add(delegation);
	}

	
	/**
	 * Ajoute une liste de lien de délégation.
	 * 
	 * @param delegations	une liste de délégations à ajouter
	 */
	public void addDelegations(List<Delegation> delegations) {
		add(delegations);
	}
	

	/**
	 * Ajoute une liste de lien de propriété.
	 * 
	 * @param delegations	une liste de propriété à ajouter
	 */
	public void addOwnerAssociations(List<OwnerAssociation> ownerAssociations) {
		add(ownerAssociations);
	}

	
	/**
	 * Renvoie la liste des délégations existentes parmi la liste de délégation
	 * passée en paramètre
	 * 
	 * @param delegations	une liste de délégations à chercher
	 */
	public List<Delegation> findDelegations(List<Delegation> delegations) {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;
		
		try {
			transaction = session.beginTransaction();
			Criteria query = session.createCriteria(Delegation.class);
			Disjunction disjonction = Restrictions.disjunction();
			for(Delegation delegation : delegations) {
				Conjunction conjunction = Restrictions.conjunction();
				conjunction
					.add(Restrictions.eq("ownerCode", delegation.getOwnerCode()))
					.add(Restrictions.eq("sheetCode", delegation.getSheetCode()))
					.add(Restrictions.eq("personCode", delegation.getPersonCode()));
				
				disjonction.add(conjunction);
			}
			
			query.add(disjonction);
			
			@SuppressWarnings("unchecked")
			List<Delegation> foundDelegations = query.list();
			
			return foundDelegations;
		} catch(HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}
	

	/**
	 * Cherche la liste des délégations effectuées par l'individu dont le code
	 * est passé en argument.
	 * 
	 * @param ownerCode	code de l'individu dont on cherche les fiches déléguées
	 * @return la liste des délégations faites par l'individu
	 */
	public List<Delegation> findGivenDelegations(String ownerCode) {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();
			Criteria query = session.createCriteria(Delegation.class);
			query.add(Restrictions.eq("ownerCode", ownerCode));

			@SuppressWarnings("unchecked")
			List<Delegation> delegations = query.list();

			return delegations;
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}

	/**
	 * Cherche la liste des délégations reçues par l'individu dont le code est
	 * passé en argument.
	 * 
	 * @param ownerCode	code de l'individu dont on cherche les délégation reçues
	 * @return la liste des délégations faites par l'individu
	 */
	public List<Delegation> findReceivedDelegations(String personCode) {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();
			Criteria query = session.createCriteria(Delegation.class);
			query.add(Restrictions.eq("personCode", personCode));

			@SuppressWarnings("unchecked")
			List<Delegation> delegations = query.list();

			return delegations;
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}

	
	/**
	 * Supprime un lien de délégation.
	 * 
	 * @param delegation	un objet délégation à supprimer
	 */
	public void removeDelegation(Delegation delegation) {
		remove(delegation);
	}

	
	/**
	 * Supprime un lien de délégation à partir de son id.
	 * 
	 * @param	id	l'id de la délégation à supprimer
	 */
	public void removeDelegationById(long id) {
		removeById(id, Delegation.class);
	}

	

	/**
	 * Supprime une liste de lien de délégation.
	 * 
	 * @param delegations	une liste de délégations à supprimer
	 */
	public void removeDelegations(List<Delegation> delegations) {
		remove(delegations);
	}

	
	/**
	 * Supprime une liste de liens de délégation à partir de leur id.
	 * 
	 * @param	ids	la liste des ids des délégation à supprimer
	 */
	public void removeDelegationsByIds(List<Long> ids) {
		removeByIds(ids, Delegation.class);
	}

	

	/**
	 * Supprime toutes les délégations.
	 */
	public void removeAllDelegations() {
		removeAll(Delegation.class);
	}

	
	/**
	 * Ajoute un lien de propriété.
	 * 
	 * @param ownerAssociation	un objet d'association à ajouter
	 */
	public void addOwnerAssociation(OwnerAssociation ownerAssociation) {
		add(ownerAssociation);
	}

	public List<OwnerAssociation> findOwnerAssociations() {
		return findAll(OwnerAssociation.class);
	}

	
	
	/**
	 * Cherche la liste des liens de propriété pour l'individu dont le code est
	 * passé en argument
	 * 
	 * @param ownerCode	code de l'individu dont on cherche les liens de propriétés
	 * @return la liste des liens de propriétés de l'individu
	 */
	public List<OwnerAssociation> findOwnerAssociations(String ownerCode) {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();
			Criteria query = session.createCriteria(OwnerAssociation.class);
			query.add(Restrictions.eq("personCode", ownerCode));

			@SuppressWarnings("unchecked")
			List<OwnerAssociation> ownerAssociations = query.list();

			return ownerAssociations;
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}
	
	

	/**
	 * Supprimer un lien de propriété.
	 * 
	 * @param ownerAssociation	un objet d'association à supprimer
	 */
	public void removeOwnerAssociation(OwnerAssociation ownerAssociation) {
		remove(ownerAssociation);
	}

	
	/**
	 * Supprime un lien de propriété à partir de son id.
	 * 
	 * @param	id	l'id de l'association de propriété à supprimer
	 */
	public void removeOwnerAssociation(long id) {
		removeById(id, OwnerAssociation.class);
	}

	
	/**
	 * Supprime une liste de liens de propriété.
	 * 
	 * @param	ownerAssociations	la liste des associations de propriété à supprimer
	 */
	public void removeOwnerAssociations(List<OwnerAssociation> ownerAssociations) {
		removeDelegationsByOwnerAndSheet(ownerAssociations);
		remove(ownerAssociations);
	}

	
	/**
	 * Supprime une liste de liens de propriété à partir de leur id.
	 * 
	 * @param	id	la liste des ids des associations de propriété à supprimer
	 */
	public void removeOwnerAssociationsByIds(List<Long> ids) {
		removeByIds(ids, OwnerAssociation.class);
	}

	
	
	/**
	 * Supprime tous les liens de propriété.
	 */
	public void removeAllOwnerAssociations() {
		removeAll(OwnerAssociation.class);
	}

	
	/**
	 * Ajout un lien père/fils.
	 * 
	 * @param	treeAssociation	l'association père/fils à ajouter
	 */
	public void addTreeAssociation(TreeAssociation treeAssociation) {
		add(treeAssociation);
	}

	
	/**
	 * Ajout une liste de liens père/fils.
	 * 
	 * @param	treeAssociations	la liste d'association père/fils à ajouter
	 */
	public void addTreeAssociations(List<TreeAssociation> treeAssociations) {
		add(treeAssociations);

	}

	
	/**
	 * Cherche les associations père/fils à partir du code du pere et du type des fils.
	 * 
	 * @param	parentCode	code du père
	 * @param	childType	type du fils
	 * @return la liste des associations père/fils trouvées
	 */
	public List<TreeAssociation> findTreeAssociations(String parentCode,
			String childType) {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();
			Criteria query = session.createCriteria(TreeAssociation.class);
			query.add(Restrictions.eq("parentCode", parentCode));
			query.add(Restrictions.eq("childType", childType));

			@SuppressWarnings("unchecked")
			List<TreeAssociation> treeAssociations = query.list();

			return treeAssociations;
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}

	
	/**
	 * Supprime une association père/fils.
	 * 
	 * @param	treeAssociation	code du père
	 */
	public void removeTreeAssociation(TreeAssociation treeAssociation) {
		remove(treeAssociation);
	}

	
	/**
	 * Supprime une liste d'associations père/fils.
	 * 
	 * @param	treeAssociations	liste des associations père/fils à supprimer
	 */
	public void removeTreeAssociations(List<TreeAssociation> treeAssociations) {
		remove(treeAssociations);

	}

	

	/**
	 * Cherche les types des fiches filles de la fiche dont le code est passé
	 * en paramètre
	 * 
	 * @param	parentCode	code de la fiche dont on cherche les types fils
	 * @return	la liste des types trouvés
	 */
	public List<String> findChildrenTypes(String parentCode) {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();

			Criteria criteria = session
					.createCriteria(TreeAssociation.class, "t1")
					.setProjection(
							Projections.distinct(Projections
									.property("childType")))
					.add(Restrictions.eq("parentCode", parentCode));

			@SuppressWarnings("unchecked")
			List<String> childrenTypes = criteria.list();

			return childrenTypes;
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}

	

	/**
	 * Cherche les types des fiches racines.
	 * 
	 * @return la liste des types racines
	 */
	public List<String> findRootTypes() {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();

			Criteria c1 = session.createCriteria(TreeAssociation.class, "t1");
			c1.setProjection(Projections.distinct(Projections
					.property("parentType")));

			DetachedCriteria c2 = DetachedCriteria.forClass(
					TreeAssociation.class, "t2");
			c2.setProjection(Projections.id());
			c2.add(Property.forName("t1.parentCode").eqProperty("t2.childCode"));

			c1.add(Subqueries.notExists(c2));

			@SuppressWarnings("unchecked")
			List<String> parentTypes = c1.list();

			return parentTypes;
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}

	
	
	/**
	 * Cherche les fiches racines (d'un type donné).
	 * 
	 * @param	type	le type des fiches racines cherchées
	 * @return	la liste des fiches racines trouvées
	 */
	public List<TreeAssociation> findRootTreeAssociationsByType(String type) {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();

			Criteria c1 = session.createCriteria(TreeAssociation.class, "t1");

			DetachedCriteria c2 = DetachedCriteria.forClass(
					TreeAssociation.class, "t2");
			c2.setProjection(Projections.id());
			c2.add(Property.forName("t1.parentCode").eqProperty("t2.childCode"));

			c1.add(Subqueries.notExists(c2));

			@SuppressWarnings("unchecked")
			List<TreeAssociation> treeAssociations = c1.list();

			return treeAssociations;
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}

	

	/**
	 * Cherche la liste des fiches simplifiées du type passé en paramètre.
	 * 
	 * @param	type	le type des fiches cherchées
	 * @return	la liste des fiches simplifiée trouvées
	 */
	public List<SmallSheet> findAllSmallSheets(String type) {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();

			@SuppressWarnings("unchecked")
			List<SmallSheet> result = session
					.createCriteria(type)
					.addOrder(Order.asc(NamingUtil.CODE))
					.setProjection(
							Projections
									.projectionList()
									.add(Projections.property(NamingUtil.CODE),
											"code")
									.add(Projections
											.property(NamingUtil.VERSION),
											"version"))
					.setResultTransformer(
							Transformers.aliasToBean(SmallSheet.class)).list();

			return result;
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}


	
	/**
	 * Cherche la liste des lien de propriété dont la fiche
	 * est du type passé en paramètre.
	 * 
	 * @param	sheetType	le type de fiches à utiliser pour chercher les propriétés
	 * @return	la liste des liens de propriétés trouvés
	 */
	public List<OwnerAssociation> findOwnerAssociationsBySheetType(String sheetType) {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();
			Criteria query = session.createCriteria(OwnerAssociation.class)
					.add(Restrictions.eq("sheetType", sheetType));

			@SuppressWarnings("unchecked")
			List<OwnerAssociation> ownerAssociation = query.list();

			return ownerAssociation;
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}

	
	/**
	 * Cherche tous les liens père/fils dont le type du père et du fils
	 * sont les types passés en paramètre.
	 * 
	 * @param	parentType	le type du père utilisé pour chercher les liens
	 * @param	childType	le type du fils utilisé pour chercher les liens
	 * @return la liste des associations père/fils trouvées
	 */
	public List<TreeAssociation> findTreeAssociationsByTypes(String parentType,
			String childType) {

		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();
			Criteria query = session.createCriteria(TreeAssociation.class);
			query.add(Restrictions.eq("parentType", parentType));
			query.add(Restrictions.eq("childType", childType));

			@SuppressWarnings("unchecked")
			List<TreeAssociation> treeAssociations = query.list();

			return treeAssociations;
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}
	
	

	/**
	 * Supprime toutes les délégations correspondant aux liens de propriétés
	 * passé en paramètres (utilise le code du propriétaire et le code de la fiche).
	 * 
	 * @param	ownerAssociations	la liste des liens de propriétés utilisés pour supprimer le délégations
	 */
	public void removeDelegationsByOwnerAndSheet(List<OwnerAssociation> ownerAssociations) {
		if (ownerAssociations == null || ownerAssociations.isEmpty()) {
			return;
		}

		Session session = hibernateUtil.getSessionFactory().openSession();
		String s = "delete from Delegation d where d.ownerCode = :ownerCode and d.sheetCode = :sheetCode";

		Query query = session.createQuery(s);
		Transaction transaction = null;
		int i = 0;

		try {
			transaction = session.beginTransaction();

			for (OwnerAssociation association : ownerAssociations) {
				query.setParameter("ownerCode", association.getPersonCode());
				query.setParameter("sheetCode", association.getSheetCode());

				query.executeUpdate();
				
				// batch :
				if (++i % hibernateUtil.getJdbcBatchSize() == 0) {
					session.flush();
					session.clear();
				}
			}

			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}



	/**
	 * Supprime tous les liens père/fils à partir du type du père et du type du fils
	 * (types passés dans les deux liste en paramètre).
	 * 
	 * @param	parentTypes	liste des types de père
	 * @param	childTypes	liste des type de fils
	 */
	public int removeTreeAssociationsByTypes(List<String> parentTypes, List<String> childTypes) {

		if (parentTypes == null || parentTypes.isEmpty()) {
			return 0;
		}

		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();
			String query = "delete from TreeAssociation t where ";
			StringBuilder builder = new StringBuilder(query);

			for (int i = 0; i < parentTypes.size(); i++) {
				builder.append("(t.parentType='");
				builder.append(parentTypes.get(i));
				builder.append("' and t.childType='");
				builder.append(childTypes.get(i));
				builder.append("') or ");
			}

			builder.delete(builder.length() - 4, builder.length());
			query = builder.toString();

			int rowCount = session.createQuery(query).executeUpdate();
			transaction.commit();

			return rowCount;
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}

	
	
	/**
	 * Cherche si un individu a les droits délégués pour une fiche.
	 * 
	 * @param	personCode	code de l'individu
	 * @param	sheetCode	code de la fiche
	 */
	public boolean personHasDelegationForSheet(String personCode,
			String sheetCode) {

		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();

			Criteria query = session.createCriteria(Delegation.class);
			query.setProjection(Projections.rowCount());
			query.add(Restrictions.eq("personCode", personCode));
			query.add(Restrictions.eq("sheetCode", sheetCode));

			long rowCount = (Long) query.uniqueResult();

			return (rowCount > 0);
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}


	
	/**
	 * Cherche si un individu est propriétaire d'une fiche.
	 * 
	 * @param	personCode	code de l'individu
	 * @param	sheetCode	code de la fiche
	 */
	public boolean personOwnsSheet(String personCode, String sheetCode) {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();

			Criteria query = session.createCriteria(OwnerAssociation.class);
			query.setProjection(Projections.rowCount());
			query.add(Restrictions.eq("personCode", personCode));
			query.add(Restrictions.eq("sheetCode", sheetCode));

			long rowCount = (Long) query.uniqueResult();

			return (rowCount > 0);
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}
	


	
	/**
	 * Ajoute une association transverse.
	 * 
	 * @param linkAssociation	association transverse à ajouter
	 */
	public void addLinkAssociation(List<LinkAssociation> linkAssociation) {
		add(linkAssociation);
	}



	/**
	 * Supprime les associations transverses à partir du type source
	 * et du type destination
	 * 
	 * @param from	type source de l'association
	 * @param to	type destination de l'association
	 * @return le nombre d'associations supprimées
	 */
	public int removeLinkAssociation(String from, String to) {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;
		
		try {
			transaction = session.beginTransaction();
			Query query = session.createQuery(
					"delete from " + LinkAssociation.class.getName() 
					+ " l where l.fromType = :from and l.toType = :to")
					.setParameter("from", from)
					.setParameter("to", to);
			int nbRow = query.executeUpdate();

			transaction.commit();
			
			return nbRow;
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}

	
	
	/**
	 * Cherche les labels des liens transverses possibles pour une fiche
	 * dont le code et le type est passé en paramètre
	 * 
	 * @param sheetCode	code de la fiche
	 * @param sheetType	type de la fiche
	 * @return la liste des labels trouvés
	 */
	public List<String> findLinkAssociationLabels(String sheetCode, 
			String sheetType) {
		
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();

			Criteria criteria = session
					.createCriteria(LinkAssociation.class)
					.setProjection(
							Projections.distinct(Projections
									.property("label")))
					.add(Restrictions.eq("fromCode", sheetCode))
					.add(Restrictions.eq("fromType", sheetType));

			@SuppressWarnings("unchecked")
			List<String> labels = criteria.list();

			return labels;
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}


	
	/**
	 * Cherche les liens transverses à partir de leur label, pour une
	 * fiche donnée.
	 * 
	 * @param	sheetCode	code de la fiche
	 * @param	sheetType	type de la fiche
	 * @param	label		le label des associations cherchées
	 */
	public List<LinkAssociation> findLinkAssociationByLabel(String sheetCode,
			String sheetType, String label) {
		Session session = hibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;

		try {
			transaction = session.beginTransaction();

			Criteria criteria = session
					.createCriteria(LinkAssociation.class)
					.add(Restrictions.eq("fromCode", sheetCode))
					.add(Restrictions.eq("fromType", sheetType))
					.add(Restrictions.eq("label", label));

			@SuppressWarnings("unchecked")
			List<LinkAssociation> associations = criteria.list();

			return associations;
		} catch (HibernateException e) {
			transaction.rollback();
			throw e;
		} finally {
			session.close();
		}
	}

}
